package com.itheima.servcie;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSON;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itheima.bean.CodeBean;
import com.itheima.dbservice.UserInfoServiceApi;
import com.itheima.dto.mongo.PushMovementDto;
import com.itheima.exception.CommonException;
import com.itheima.mongoservice.FriendServiceApi;
import com.itheima.mongoservice.MovementServiceApi;
import com.itheima.mongoservice.TanhuaServiceApi;
import com.itheima.mongoservice.VisitorsServiceApi;
import com.itheima.pojo.UserInfo;
import com.itheima.pojo.mongo.*;
import com.itheima.template.OssTemplate;
import com.itheima.vo.MovementsVo;
import com.itheima.vo.PersonalInfoVo;
import com.itheima.vo.mongo.AllVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.bson.types.Code;
import org.bson.types.ObjectId;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class MovementsService {
    @DubboReference
    private MovementServiceApi movementServiceApi;
    @DubboReference
    private VisitorsServiceApi visitorsServiceApi;
    @DubboReference
    private TanhuaServiceApi tanhuaServiceApi;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private TanhuaService tanhuaService;
    @Autowired
    private OssTemplate ossTemplate;
    @Autowired
    private AmqpTemplate amqpTemplate;
    @DubboReference
    private UserInfoServiceApi userInfoServiceApi;
    @DubboReference
    private FriendServiceApi friendServiceApi;

    public Integer love(String id) {
        //获取当前用户id
        Long uid = Convert.toLong(stringRedisTemplate.opsForValue().get(CodeBean.ID));
        //检查Redis是否已存入喜欢的动态信息
        String list = stringRedisTemplate.opsForValue().get(CodeBean.MOVEMENT_LOVE_HASHKEY + uid);
        if (ObjectUtil.isNull(list)){
            //创建动态喜欢的集合
            List<String> loveIds = new ArrayList<>();
            loveIds.add(id);
            String ids = JSONUtil.toJsonStr(loveIds);
            //存入Redis
            stringRedisTemplate.opsForValue().set(CodeBean.MOVEMENT_LOVE_HASHKEY + uid, ids);
        }else {
            List<String> loveIds = JSONUtil.toList(JSONUtil.parseArray(list), String.class);
            //检查id是否存在
            if (loveIds.contains(id)){
                throw new CommonException("动态已喜欢，无法再点");
            }
            loveIds.add(id);
            String ids = JSONUtil.toJsonStr(loveIds);
            //存入Redis
            stringRedisTemplate.opsForValue().set(CodeBean.MOVEMENT_LOVE_HASHKEY + uid, ids);
        }
        //喜欢数+1
        Movement movementInfo = movementServiceApi.getMovementInfo(Convert.toStr(id));
        movementInfo.setLoveCount(movementInfo.getLoveCount() + 1);
        //存入MongoDB
        movementServiceApi.updateMovement(movementInfo);
        //返回
        return movementInfo.getLoveCount();
    }

    public Object[] visitors() {
        //获取当前登录者id
        Long uid = Convert.toLong(stringRedisTemplate.opsForValue().get(CodeBean.ID));
        //查询访问的用户信息
        List<Visitors> visitorsList = visitorsServiceApi.getVisitors(uid);
        //根据id查询访问者的信息
        return visitorsList.stream().map(item -> {
            UserInfo userInfo = userInfoServiceApi.getUserInfoById(item.getVisitorUserId());
            //复制返回数据到vo
            PersonalInfoVo personalInfoVo = new PersonalInfoVo();
            BeanUtil.copyProperties(userInfo, personalInfoVo, "tags");
            String[] tags = userInfo.getTags().split(",");
            personalInfoVo.setTags(tags);
            //获取缘分信息
            RecommendUser recommendUser = tanhuaServiceApi.getRecommendationUser(item.getVisitorUserId(), uid);
            //封装缘分值
            personalInfoVo.setFateValue(ObjectUtil.isNull(recommendUser) ? 50 : Convert.toInt(recommendUser.getScore()));

            return personalInfoVo;
        }).toArray();
    }

    public AllVo getAllMyMovements(Integer page, Integer pagesize, Long userId) {
        List<Movement> myMovements = movementServiceApi.getMyMovements(page, pagesize, userId);
        AllVo allVo = new AllVo();
        List<MovementsVo> list = new ArrayList<>();
        return getAllVo(page, pagesize, myMovements, list, allVo);
    }

    public AllVo friendMovement(Integer page, Integer pagesize) {
        //取得当前登录者id
        Long uid = Convert.toLong(stringRedisTemplate.opsForValue().get(CodeBean.ID));
        //查询对应好友集合
        List<Friend> friends = movementServiceApi.getUserFriend(uid);
        //查询朋友动态集合
        if (friends == null){
            throw new CommonException("好友动态为空");
        }
        //查询好友和登录者的动态时间线
        List<MovementTimeLine> movementTimeLine = movementServiceApi.getMovementTimeline(page, pagesize, uid);
        //查询好友和自己动态
        List<Movement> movements = movementServiceApi.getMovements(page, pagesize, movementTimeLine);
        //获取好友信息
        List<MovementsVo> list = new ArrayList<>();

        AllVo allVo = new AllVo();
        return getAllVo(page, pagesize, movements, list, allVo);
    }

    //封装返回数据AllVo
    private AllVo getAllVo(Integer page, Integer pagesize, List<Movement> movements, List<MovementsVo> list, AllVo allVo) {
        for (Movement movement : movements) {
            if (ObjectUtil.isNull(movement)){
                continue;
            }
            //封装MovementsVo
            MovementsVo movementsVo = getMovementsVo(movement);
            list.add(movementsVo);
        }
        allVo.setItems(list.toArray());
        allVo.setPagesize(pagesize);
        allVo.setPage(page);
        allVo.setCounts(list.size());
        allVo.setPages(list.size()/ pagesize +1);
        return allVo;
    }

    //封装MovementsVo
    private MovementsVo getMovementsVo(Movement movement) {
        if (ObjectUtil.isNull(movement)){
            return new MovementsVo();
        }
        UserInfo userInfo = userInfoServiceApi.getUserInfoById(movement.getUserId());
        //封装
        MovementsVo movementsVo = new MovementsVo();
        BeanUtil.copyProperties(userInfo, movementsVo, "tags");
        movementsVo.setTags(userInfo.getTags().split(","));

        BeanUtil.copyProperties(movement, movementsVo);
        movementsVo.setImageContent(movement.getMedias().toArray(new String[0]));
        //todo：多少时间前
//        movementsVo.setCreateDate(Convert.toStr(movement.getCreated()));
        movementsVo.setCreateDate(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(movement.getCreated())));
        //评论数
        movementsVo.setCommentCount(movement.getCommentCount() != null ? movement.getCommentCount() : 0);
        //点赞数
        movementsVo.setLikeCount(movement.getLikeCount() != null ? movement.getLikeCount() : 0);
        //喜欢数
        movementsVo.setLoveCount(movement.getLoveCount() != null ? movement.getLoveCount() : 0);
        //后面处理
        movementsVo.setDistance("759");
        String uid = stringRedisTemplate.opsForValue().get(CodeBean.ID);
        Object isHasLike = stringRedisTemplate.opsForHash().get(CodeBean.MOVEMENTS_INTERACT_KEY + movement.getId(),
                                                                CodeBean.MOVEMENT_LIKE_HASHKEY + uid);
        if (ObjectUtil.isNull(isHasLike)){
            movementsVo.setHasLiked(0);
        }else {
            movementsVo.setHasLiked(Convert.toInt(isHasLike));
        }
        movementsVo.setHasLoved(0);
        return movementsVo;
    }

    public void pushMovement(PushMovementDto pushMovementDto, MultipartFile[] imageContent){
        try {
            //获取当前用户id
            String uid = stringRedisTemplate.opsForValue().get(CodeBean.ID);
            log.info("当前登录用户id：{}", uid);
            //检查用户被冻结范围
            log.info(CodeBean.FREEZE_USER + uid);
            String map1 = Convert.toStr(stringRedisTemplate.opsForValue().get(CodeBean.FREEZE_USER + uid));
            Map freezeMap = JSONUtil.toBean(map1, Map.class);
            //检查是否有该用户
            if (freezeMap.size() != 0){
                //检查用户被冻结范围，1为冻结登录，2为冻结发言，3为冻结发布动态
                Integer freezingRange = Convert.toInt(freezeMap.get("freezingRange"));
                if (ObjectUtil.equal(3, freezingRange)){
                    throw new CommonException("您已被禁止发布动态");
                }
            }
            //判断用户输入的内容是否为空
            if (ObjectUtil.isNull(pushMovementDto.getTextContent())){
                throw new CommonException("未输入内容，无法发布");
            }
            //封装数据
            Movement movement = new Movement();
            movement.setTextContent(pushMovementDto.getTextContent());
            movement.setUserId(Convert.toLong(uid));
            movement.setLocationName(pushMovementDto.getLocation());
            movement.setLongitude(pushMovementDto.getLongitude());
            movement.setLatitude(pushMovementDto.getLatitude());
            //获取图片在阿里云的地址
            List<String> medias = new ArrayList<>();
            for (MultipartFile multipartFile : imageContent) {
                String imageUrl = ossTemplate.upload(multipartFile.getOriginalFilename(), multipartFile.getInputStream());
                medias.add(imageUrl);
            }
            movement.setMedias(medias);
            String movementId = movementServiceApi.pushMovement(movement);
            //开启人工智能审核(发送消息给监听器)
            amqpTemplate.convertSendAndReceive("tanhua.audit.exchange", "audit.movement", movementId);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public AllVo recommend(Integer page, Integer pagesize) {
        //获取当前用户id
        Long uid = Convert.toLong(stringRedisTemplate.opsForValue().get(CodeBean.ID));
        //取出推荐的pid(id为死数据106)
        String pidArr = stringRedisTemplate.opsForValue().get(CodeBean.MOVEMENTS_RECOMMEND + 106);
        assert pidArr != null;
        String[] pids = pidArr.split(",");
        List<MovementsVo> list = new ArrayList<>();
        AllVo allVo = new AllVo();
        //判断pid是否用完
        if (pids.length/pagesize < page){
            for (String pid : pids) {
                List<Movement> movements = movementServiceApi.getMovementsByPid(page, pagesize, Convert.toLong(pid));
                return getAllVo(page, pagesize, movements, list, allVo);
            }
        }else {
            //随机推荐非好友用户动态
            List<Movement> movements = movementServiceApi.randomMovement(page, pagesize);
            //查找自己和好友id
            List<Friend> friends = friendServiceApi.findFriends(uid);
            //收集好友动态
            List<Movement> delete = new ArrayList<>();
            for (Movement movement : movements) {
                for (Friend friend : friends) {
                    if (Objects.equals(movement.getUserId(), friend.getFriendId())){
                        delete.add(movement);
                    }
                }
            }
            //剔除好友动态
            for (Movement movement : delete) {
                movements.remove(movement);
            }
            //剔除自己动态
            movements.removeIf(movement -> Objects.equals(movement.getUserId(), uid));

            return getAllVo(page, pagesize, movements, list, allVo);
        }
        return allVo;
    }

    public MovementsVo movementInfo(String id) {
        Movement movement = movementServiceApi.getMovementInfo(id);
        if (ObjectUtil.isNull(movement)){
            throw new CommonException("动态不存在");
        }
        return getMovementsVo(movement);
    }

    public Integer unlove(String id) {
        //获取当前用户id
        Long uid = Convert.toLong(stringRedisTemplate.opsForValue().get(CodeBean.ID));
        //查询对应动态
        Movement movementInfo = movementServiceApi.getMovementInfo(id);
        if (ObjectUtil.isNull(movementInfo)){
            throw new CommonException("动态不存在");
        }
        //获取喜欢的动态id集合
        String list = stringRedisTemplate.opsForValue().get(CodeBean.MOVEMENT_LOVE_HASHKEY + uid);
        if (ObjectUtil.isNull(list)){
            return movementInfo.getLoveCount() - 1;
        }
        List<String> ids = JSONUtil.toList(JSONUtil.parseArray(list), String.class);
        //检查是否包含
        if (!ids.contains(id)){
            throw new CommonException("动态未喜欢，无法取消");
        }
        //移除
        ids.remove(id);
        //存入redis
        stringRedisTemplate.opsForValue().set(CodeBean.MOVEMENT_LOVE_HASHKEY + uid, JSONUtil.toJsonStr(ids));
        //更新数据库
        movementInfo.setLoveCount(movementInfo.getLoveCount() - 1);
        movementServiceApi.updateMovement(movementInfo);
        return movementInfo.getLoveCount() - 1;
    }
}
